<script setup lang="ts">
import {
  ElButton,
  ElDialog,
  ElDatePicker,
  ElFormItem,
  FormRules,
  ElSelect,
  ElInput,
  ElIcon,
  ElOption,
  ElScrollbar,
  FormInstance,
  ElMessage
} from "element-plus";
import {taskOptions, TaskType, mapScaleOptions} from 'common/src/utils/special';
import {CircleClose, CirclePlus, LocationFilled} from "@element-plus/icons-vue";
import {addTask, editTask, EditTaskData, TaskItem, impDiyPoints, diyPointsData} from "@/services/task";
import {getCustomLocalTimeFormat, getCustomUTCTimeFormat, getTimestampFromCustomFormatZ} from "common/src/utils/time";
import {useAppStore, useWeatherStore, useUserStore,useMapEventStore} from "@/store";
import { MapTool, createPointPickHandlers, createRegionPickHandlers, createDiyRouteDrawHandlers } from '@/store/map-event';
import {latDirection, latFloatFilter, lonDirection, lonFloatFilter} from "common/src/utils/lnglat";
import {getPortFromStr, PortOption} from "common/src/utils/port";
import {routeOptions} from "common/src/utils/special";
import { Marker} from "mapbox-gl";
import {getParkMarker} from "common/src/utils/ship";
import {updateTaskRegionSrc} from "common/src/utils/layer";
import CustomRoute from "@/components/table/custom-route.vue";
import {useRoute} from 'vue-router'
import {nextTick} from 'vue'

const router = useRoute()

interface Props {
  visible: boolean;
  showMask?: boolean;
  center?: boolean;
}

interface Emits {
  (e: "update:visible", visible: boolean): void;

  (e: 'update'): void;
}

enum RoutePointType {
  port = 'port',
  point = 'point',
}

const routePointOptions = [
  {value: RoutePointType.port, label: '港口'},
  {value: RoutePointType.point, label: '点位'},
];

interface RoutePoint {
  lon?: number;
  lat?: number;
  inputType?: RoutePointType;
  portId?: number;
  name: string;
  lonDirection: string;
  latDirection: string;
  lonValue: string;
  latValue: string;
}


interface DiyPoint {
  longitude: number | string;
  latitude: number | string;
}

const initDiyPoint: DiyPoint = {
  longitude: '',
  latitude: '',
};


const initRoutePoint: RoutePoint = {
  inputType: RoutePointType.port,
  portId: undefined,
  lon: undefined,
  lat: undefined,
  name: '',
  lonDirection: 'E',
  lonValue: '',
  latDirection: 'N',
  latValue: '',
};

const initRegionPoint = {
  lonDirection: 'E',
  lonValue: '',
  latDirection: 'N',
  latValue: '',
};

type RegionPoint = typeof initRegionPoint;

const initTaskInfo = () => {
  return {
    id: 0,
    code: '',
    mmsi: '',
    speed: '12',
    // windSpeed: '25',
    // waveHeight: '5',
    type: TaskType.taskPrepare,
    etd: new Date(),
    points: [
      {...initRoutePoint},
      {...initRoutePoint},
    ],
    diyPoints: [],
    regionLeftTop: {...initRegionPoint},
    regionRightBottom: {...initRegionPoint},
    route: [1],
    safety: 3,
    mapScale: 20,
    /** 固定时间航线预计到达时间 */
    eta: new Date(),
    /** 固定时间到达允许误差(小时) */
    tolerance: '1',
    alertWindSpeed: '20',
    alertWaveHeight: '4',
    roll: '',
    pitch: '',
  };
};

const editMarkerClass = 'edit-park-marker';

const props = withDefaults(defineProps<Props>(), {
  showMask: false,
  center: false,
});
const emits = defineEmits<Emits>();
const loading = ref(false);
const editTaskInfo = reactive(initTaskInfo());
const formRef = ref<FormInstance>();
const appStore = useAppStore();
const weatherStore = useWeatherStore();
const userStore = useUserStore();
const mapEventStore = useMapEventStore()
const portOptions = ref<PortOption[]>([]);
/** 记录已选的港口 */
const portOptionsChosen = ref<PortOption[]>([]);
const portLoading = ref(false);
const activeInputIdx = ref(-1);
const pointMarkers = ref<Marker[]>([]);
/** 任务编号是否手动更新过，手动更新后不再自动更新 */
const codeChangedManually = ref(false);

const numReg = /^[0-9]+(\.[0-9]{0,2})?$/;

/**
 * 将地图点击与绘制逻辑迁入 mapEventStore：
 * - pointPick: 起/终/途径点拾取（依赖 activeInputIdx 指明当前行）
 * - regionLTPick / regionRBPick: 任务区域两角拾取
 * - diyRouteDraw: 自定义航线绘制
 */
const registerMapEventHandlers = () => {
  const map = weatherStore.map as any;
  if (!map) return;

  // 1) 路线点拾取
  mapEventStore.registerTool(
      MapTool.pointPick,
      createPointPickHandlers({
        map,
        getActiveInputIdx: () => activeInputIdx.value,
        setActiveInputIdx: (v) => (activeInputIdx.value = v),
        onPickRoutePoint: (idx, lng, lat) => {
          const lngLat = {
            latValue: Math.abs(lat).toFixed(2),
            lonValue: Math.abs(lng).toFixed(2),
            latDirection: lat > 0 ? 'N' : 'S',
            lonDirection: lng > 0 ? 'E' : 'W',
          };
          Object.assign(editTaskInfo.points[idx], lngLat);
          handlePointUpdate(idx);
        },
      })
  );

  // 2) 区域左上
  mapEventStore.registerTool(
      MapTool.regionLTPick,
      createRegionPickHandlers({
        map,
        title: '点选·区域左上',
        onPick: (lng, lat) => {
          const lngLat = {
            latValue: Math.abs(lat).toFixed(2),
            lonValue: Math.abs(lng).toFixed(2),
            latDirection: lat > 0 ? 'N' : 'S',
            lonDirection: lng > 0 ? 'E' : 'W',
          };
          Object.assign(editTaskInfo.regionLeftTop, lngLat);
          handleRegionUpdate();
        },
      })
  );

  // 3) 区域右下
  mapEventStore.registerTool(
      MapTool.regionRBPick,
      createRegionPickHandlers({
        map,
        title: '点选·区域右下',
        onPick: (lng, lat) => {
          const lngLat = {
            latValue: Math.abs(lat).toFixed(2),
            lonValue: Math.abs(lng).toFixed(2),
            latDirection: lat > 0 ? 'N' : 'S',
            lonDirection: lng > 0 ? 'E' : 'W',
          };
          Object.assign(editTaskInfo.regionRightBottom, lngLat);
          handleRegionUpdate();
        },
      })
  );

  // 4) 自定义航线绘制
  mapEventStore.registerTool(
      MapTool.diyRouteDraw,
      createDiyRouteDrawHandlers({
        start: () => customRouteRef.value?.startDraw?.(),
        stop:  () => {
          (customRouteRef.value as any)?.stopDraw?.();
          (customRouteRef.value as any)?.endDraw?.();
          (customRouteRef.value as any)?.cancelDraw?.();
        },
      })
  );
};

// 地图就绪即注册（HMR/重渲染安全）
watch(
    () => weatherStore.map,
    (m) => { if (m) registerMapEventHandlers(); },
    { immediate: true }
);

// 模板高亮辅助
const isPointIdxActive = (idx: number) =>
    mapEventStore.isActive(MapTool.pointPick) && activeInputIdx.value === idx;
const isRegionLTPicking = computed(() => mapEventStore.isActive(MapTool.regionLTPick));
const isRegionRBPicking = computed(() => mapEventStore.isActive(MapTool.regionRBPick));

// 区域图标开关
const toggleRegionLTPick = () => {
  // 进入区域点选前，确保不再保持某个路线点行处于激活索引
  activeInputIdx.value = -1;
  if (mapEventStore.isActive(MapTool.regionLTPick)) {
    mapEventStore.deactivate(MapTool.regionLTPick);
  } else {
    mapEventStore.activate(MapTool.regionLTPick);
  }
};
const toggleRegionRBPick = () => {
  // 进入区域点选前，确保不再保持某个路线点行处于激活索引
  activeInputIdx.value = -1;
  if (mapEventStore.isActive(MapTool.regionRBPick)) {
    mapEventStore.deactivate(MapTool.regionRBPick);
  } else {
    mapEventStore.activate(MapTool.regionRBPick);
  }
};

const lngLatValidator = (lonValue: string, latValue: string, callback: any) => {
  if (!lonValue || !latValue) {
    callback('请输入点位');
  } else {
    const lonNum = Number(lonValue);
    const latNum = Number(latValue);
    if (Number.isNaN(lonNum) || Number.isNaN(latNum)) {
      callback('请输入数字');
    } else if (!numReg.test(lonValue) || !numReg.test(latValue)) {
      callback('请输入正数，最多两位小数');
    } else if (lonNum > 180 || lonNum < 0) {
      callback('经度在0～180之间');
    } else if (latNum > 90 || latNum < 0) {
      callback('纬度在0～90之间');
    }
  }

};

const pointValidator = (point: RoutePoint, callback: any) => {
  const {inputType, portId, lat, lon, lonValue, latValue} = point;
  if (inputType === RoutePointType.port) {
    if (portId === undefined || lat === undefined || lon === undefined) {
      callback('请选择港口');
    }
  } else {
    lngLatValidator(lonValue, latValue, callback);
  }
  callback();
};

const regionValidator = (point: RegionPoint, callback: any) => {
  const {lonValue, latValue} = point;
  lngLatValidator(lonValue, latValue, callback);
  callback();
};

const NumberRule = {pattern: numReg, message: '请输入正数，最多两位小数', trigger: ['blur', 'change']};

const rules = reactive<FormRules>({
  code: [
    {required: true, message: '请输入任务编号', trigger: ['blur']},
    {max: 50, message: '最长50位字符', trigger: ['change']},
  ],
  mmsi: [
    {required: true, message: '请选择舰船号', trigger: ['blur', 'change']},
  ],
  type: [
    {required: true, message: '请选择任务阶段', trigger: ['blur']},
  ],
  etd: [
    {required: true, message: '请选择起航时间', trigger: ['blur']},
  ],
  route: [
    {type: 'array', required: true, min: 1, message: '请选择航线类型', trigger: ['change', 'blur']},
  ],
  speed: [
    {required: true, message: '请输入航行速度！', trigger: ['blur', 'change']},
    {...NumberRule},
    {
      validator: (_rule: any, value: string, callback: any) => {
        // 先判断空值（包括空字符串和仅空白）
        if (value === '' || value == null || (typeof value === 'string' && value.trim() === '')) {
          callback('请输入航行速度！');
          return;
        }
        // 再判断是否为 0
        if (Number(value) === 0) {
          callback('航速不能为0！');
        } else {
          callback();
        }
      },
      trigger: ['blur', 'change'],
    },
  ],
  mapScale: [
    {required: true, message: '请选择空间精度', trigger: ['blur']},
  ],
});

const show = computed({
  get() {
    return props.visible;
  },
  set(visible: boolean) {
    emits("update:visible", visible);
  },
});

const handlePointUpdate = (idx: number) => {
  const point = editTaskInfo.points[idx];
  let invalid = false;
  pointValidator(point, (message?: string) => {
    if (message) {
      invalid = true;
    }
  });
  const marker = pointMarkers.value[idx];
  if (!invalid) {
    const {lat, lon} = getPointLonAndLat(point);
    marker.setLngLat([lon, lat]).addTo(weatherStore.map as any);
    // 终点更新时：仅在“新建任务”或非战术航海下，同步左上角点位；
    // 若是编辑任务且为战术航海（warStart），则不再同步左上角
    const isEditingWar = editTaskInfo.id !== 0 && editTaskInfo.type === TaskType.warStart;
    if (idx === editTaskInfo.points.length - 1 && !isEditingWar) {
      Object.assign(editTaskInfo.regionLeftTop, {
        latValue: Math.abs(lat).toFixed(2),
        lonValue: Math.abs(lon).toFixed(2),
        latDirection: lat > 0 ? 'N' : 'S',
        lonDirection: lon > 0 ? 'E' : 'W',
      });
    }
  } else {
    marker.remove();
  }
};

const handleAllPointUpdate = () => {
  editTaskInfo.points.forEach((_point, idx) => {
    handlePointUpdate(idx);
  });
};

const handleRegionUpdate = () => {
  const {regionLeftTop, regionRightBottom, type} = editTaskInfo;
  let invalid = false;
  if (type === TaskType.warStart) {
    regionValidator(regionLeftTop, (message?: string) => {
      if (message) {
        invalid = true;
      }
    });
    regionValidator(regionRightBottom, (message?: string) => {
      if (message) {
        invalid = true;
      }
    });
  } else {
    invalid = true;
  }
  if (!invalid) {
    const ltLatitude = latFloatFilter(regionLeftTop.latDirection, regionLeftTop.latValue);
    const ltLongitude = lonFloatFilter(regionLeftTop.lonDirection, regionLeftTop.lonValue);
    const rbLatitude = latFloatFilter(regionRightBottom.latDirection, regionRightBottom.latValue);
    const rbLongitude = lonFloatFilter(regionRightBottom.lonDirection, regionRightBottom.lonValue);
    updateTaskRegionSrc(weatherStore.map as any, [[ltLongitude, ltLatitude], [rbLongitude, rbLatitude]]);
  } else {
    updateTaskRegionSrc(weatherStore.map as any);
  }
};

const handleTaskStageUpdate = () => {
  // 任务筹划阶段只能选择最短距离航线类型
  const {type} = editTaskInfo;
  if (type === TaskType.taskPrepare) {
    editTaskInfo.route = [1];
  }
  handleRegionUpdate();
  // 当阶段切换为非 warStart 时，若区域点选工具处于激活则关闭，避免与其他工具并存
  if (editTaskInfo.type !== TaskType.warStart) {
    if (mapEventStore.isActive(MapTool.regionLTPick)) mapEventStore.deactivate(MapTool.regionLTPick);
    if (mapEventStore.isActive(MapTool.regionRBPick)) mapEventStore.deactivate(MapTool.regionRBPick);
  }
};

const querySearchPort = async (str: string) => {
  portLoading.value = true;
  const options = await getPortFromStr(str);
  portOptionsChosen.value.forEach((optionChosen) => {
    if (!options.some(option => option.id === optionChosen.id)) {
      options.push(optionChosen);
    }
  })
  portOptions.value = options;
  portLoading.value = false;
};

const handleSelectPort = (portId: number, idx: number) => {
  const port = portOptions.value.find(option => option.id === portId);
  if (port) {
    if (!portOptionsChosen.value.some(option => option.id === portId)) {
      portOptionsChosen.value.push(port);
    }
  }
  editTaskInfo.points[idx].name = port?.text || '';
  editTaskInfo.points[idx].lon = port?.pilotLon || port?.lon;
  editTaskInfo.points[idx].lat = port?.pilotLat || port?.lat;
  handlePointUpdate(idx);
};

const handleClearPort = (idx: number) => {
  editTaskInfo.points[idx].name = '';
  editTaskInfo.points[idx].lon = undefined;
  editTaskInfo.points[idx].lat = undefined;
  handlePointUpdate(idx);
};

const getPointLabel = (idx: number) => {
  if (idx === 0) {
    return '起点';
  } else if (idx === editTaskInfo.points.length - 1) {
    return '终点';
  } else {
    return '途径';
  }
};

const getSwitchLonDirection = (lonDirection: string) => {
  if (lonDirection === 'W') {
    return 'E';
  } else {
    return 'W';
  }
};

const getSwitchLatDirection = (latDirection: string) => {
  if (latDirection === 'N') {
    return 'S';
  } else {
    return 'N';
  }
};

const updatePointLonDirection = (idx: number, lonDirection: string) => {
  editTaskInfo.points[idx].lonDirection = getSwitchLonDirection(lonDirection);
  handlePointUpdate(idx);
};

const updatePointLatDirection = (idx: number, latDirection: string) => {
  editTaskInfo.points[idx].latDirection = getSwitchLatDirection(latDirection);
  handlePointUpdate(idx);
};

// 新增：切换到点位时填充两位小数经纬度
const handlePointInputTypeChange = (idx: number) => {
  const p = editTaskInfo.points[idx];
  // 若从“点位”切回“港口”，且当前正处于该行的点选模式，则退出点选以避免残留监听
  if (p.inputType !== RoutePointType.point && mapEventStore.isActive(MapTool.pointPick) && activeInputIdx.value === idx) {
    mapEventStore.deactivate(MapTool.pointPick);
  }
  // 当切换到“点位”时，用已有经纬度填充输入框，并统一两位小数
  if (p.inputType === RoutePointType.point) {
    // 优先从数值 lon/lat 取，如果没有则尝试把原有字符串规范为两位
    if (typeof p.lon === 'number' && typeof p.lat === 'number') {
      p.lonDirection = p.lon > 0 ? 'E' : 'W';
      p.latDirection = p.lat > 0 ? 'N' : 'S';
      p.lonValue = Math.abs(p.lon).toFixed(2);
      p.latValue = Math.abs(p.lat).toFixed(2);
    } else {
      if (p.lonValue != null && p.lonValue !== '') {
        const v = Number(p.lonValue);
        if (!Number.isNaN(v)) p.lonValue = Math.abs(v).toFixed(2);
      }
      if (p.latValue != null && p.latValue !== '') {
        const v = Number(p.latValue);
        if (!Number.isNaN(v)) p.latValue = Math.abs(v).toFixed(2);
      }
    }
  }
  // 触发一次地图与校验联动
  handlePointUpdate(idx);
};

const updateRegionLonDirection = (point: RegionPoint) => {
  point.lonDirection = getSwitchLonDirection(point.lonDirection);
  handleRegionUpdate();
};

const updateRegionLatDirection = (point: RegionPoint) => {
  point.latDirection = getSwitchLatDirection(point.latDirection);
  handleRegionUpdate();
};

const addPoint = (idx: number) => {
  if (activeInputIdx.value > idx) {
    activeInputIdx.value += 1;
  }
  editTaskInfo.points.splice(idx + 1, 0, {...initRoutePoint});
  const marker = getParkMarker('经', idx + 1, editMarkerClass);
  pointMarkers.value.splice(idx + 1, 0, marker as any);
  // 后续的途径点marker都需要重新创建
  let i = idx + 2;
  while (i < pointMarkers.value.length - 1) {
    pointMarkers.value[i]?.remove();
    pointMarkers.value[i] = getParkMarker('经', i, editMarkerClass) as any;
    i++;
  }
  handleAllPointUpdate();
};

const removePoint = (idx: number) => {
  if (activeInputIdx.value > idx) {
    activeInputIdx.value -= 1;
  } else if (activeInputIdx.value === idx) {
    // 取消地图选择
    toggleActivePointSelect(idx);
  }
  editTaskInfo.points.splice(idx, 1);
  const markers = pointMarkers.value.splice(idx, 1);
  // 后续的途径点marker都需要重新创建
  let i = idx;
  while (i < pointMarkers.value.length - 1) {
    pointMarkers.value[i]?.remove();
    pointMarkers.value[i] = getParkMarker('经', i, editMarkerClass) as any;
    i++;
  }
  handleAllPointUpdate();
  markers.forEach(item => item?.remove());
};

const handleCancelEdit = () => {
  mapEventStore.deactivateAll();
  show.value = false;
};

const onDialogBeforeClose = (done: () => void) => {
  // 通过右上角关闭/遮罩关闭时，统一调用已有的清理逻辑
  handleCancelEdit();
  // 调用 Element Plus 的关闭回调，确保弹窗关闭
  done();
};

const getPointLonAndLat = (point: RoutePoint) => {
  let lon = 0, lat = 0;
  if (point.inputType === RoutePointType.point) {
    lon = lonFloatFilter(point.lonDirection, point.lonValue);
    lat = latFloatFilter(point.latDirection, point.latValue);
  } else {
    lon = point.lon ?? 0;
    lat = point.lat ?? 0;
  }
  return {lat, lon};
};

const handleSaveEdit = async () => {
  const valid = await formRef.value?.validate();
  if (!valid) {
    return;
  }
  // ✅ 校验：若仅有起点与终点且两者坐标一致，则禁止提交（但当且仅当选择了“自定义航线”[6] 时跳过该校验）
  const isOnlyCustom = Array.isArray(editTaskInfo.route) && editTaskInfo.route.length === 1 && editTaskInfo.route[0] === 6;
  if (!isOnlyCustom) {
    const pts = editTaskInfo.points || []
    if (pts.length === 2) {
      const start = getPointLonAndLat(pts[0])
      const end = getPointLonAndLat(pts[1])
      const eps = 1e-8
      const same =
          Math.abs(start.lat - end.lat) < eps &&
          Math.abs(start.lon - end.lon) < eps
      if (same) {
        ElMessage({type: 'warning', message: '起点与终点一致！'})
        return
      }
    }
  }

  // 校验：固定时间航线时，eta 不能早于 etd
  if (editTaskInfo.route.includes(3)) {
    if (editTaskInfo.eta < editTaskInfo.etd) {
      ElMessage({
        type: 'warning',
        message: '到达时间不能早于起航时间',
      });
      return;
    }
  }
  loading.value = true;
  try {
    const {
      // waveHeight, windSpeed,
      id, mmsi, code, type, etd, points, diyPoints, route,
      regionLeftTop, regionRightBottom, speed,
      mapScale, eta, tolerance, alertWaveHeight, alertWindSpeed, roll, pitch
    } = editTaskInfo;
    const data: EditTaskData = {
      mmsi,
      name: code,
      taskStage: type,
      ptdUtc: getCustomUTCTimeFormat(etd, 'YYYY-MM-DD HH:mm:ss'),
      sog: Number(speed),
      points: points.map(point => {
        const {lat, lon} = getPointLonAndLat(point);
        let id: number | null = null, name = '';
        if (point.inputType === RoutePointType.port && point.portId) {
          id = point.portId;
          name = point.name;
        }
        return {
          latitude: lat,
          longitude: lon,
          id, name,
        };
      }),
      diyPoints,
      routeType: route,
      safetyRating: 3,
      mapScale,
      comment: '',
    };
    // 如果是自定义航线且 diyPoints 有至少两个点，则替换 points 为首尾点
    if (editTaskInfo.route.length === 1 && editTaskInfo.route[0] === 6 && Array.isArray(editTaskInfo.diyPoints) && editTaskInfo.diyPoints.length >= 2) {
      const first = editTaskInfo.diyPoints[0];
      const last = editTaskInfo.diyPoints[editTaskInfo.diyPoints.length - 1];
      data.points = [
        {
          latitude: first.latitude,
          longitude: first.longitude,
          id: null,
          name: '',
        },
        {
          latitude: last.latitude,
          longitude: last.longitude,
          id: null,
          name: '',
        }
      ];
    }
    if (editTaskInfo.type === TaskType.warStart) {
      data.taskLtLatitude = latFloatFilter(regionLeftTop.latDirection, regionLeftTop.latValue);
      data.taskLtLongitude = lonFloatFilter(regionLeftTop.lonDirection, regionLeftTop.lonValue);
      data.taskRbLatitude = latFloatFilter(regionRightBottom.latDirection, regionRightBottom.latValue);
      data.taskRbLongitude = lonFloatFilter(regionRightBottom.lonDirection, regionRightBottom.lonValue);
    }
    if (editTaskInfo.type !== TaskType.taskPrepare) {
      data.alertWaveHeight = Number(alertWaveHeight);
      data.alertWindSpeed = Number(alertWindSpeed);
    }
    if (route.includes(5)) {
      data.roll = Number(roll);
      data.pitch = Number(pitch);
    }
    if (route.includes(3)) {
      data.eta = getCustomUTCTimeFormat(eta, 'YYYY-MM-DD HH:mm:ss');
      data.tolerance = Number(tolerance) * 3600;
    }
    let taskCode = 0;
    if (id === 0) {
      const res = await addTask(data);
      taskCode = res.code;
    } else {
      const res = await editTask(id, data);
      taskCode = res.code;
    }
    show.value = false;
    await mapEventStore.deactivateAll();
    if (taskCode === 0) {
      ElMessage({
        type: 'success',
        message: '操作成功',
      });
    } else {
      let message = '部分任务执行失败';
      switch (taskCode) {
        case 10000:
          message = '最短距离航线生成失败';
          break;
        case 10001:
          message = '海洋阈值航线生成失败';
          break;
        case 10002:
          message = '固定时间航线生成失败';
          break;
        case 10003:
          message = '最快速航线生成失败';
          break;
        case 10004:
          message = '姿态阈值航线生成失败';
          break;
        case 10005:
          message = '自定义航线生成失败';
          break;
        case 10006:
          message = '避台航线生成失败';
          break;
        case 11000:
          message = '发现更优航线，已自动生成避台航线';
          break;
      }
      ElMessage({
        type: 'warning',
        message,
        duration: 3000,
        // showClose: true,
      });
    }
    emits('update');
  } catch {
    ElMessage({
      type: 'warning',
      message: '操作失败，请重试',
    });
  } finally {
    loading.value = false;
  }
};

const handleEditTask = (task?: TaskItem) => {
  codeChangedManually.value = false;
  formRef.value?.clearValidate();
  pointMarkers.value.forEach(marker => marker.remove());
  pointMarkers.value = [];
  const startMarker = getParkMarker('起', 0, editMarkerClass);
  const endMarker = getParkMarker('终', 0, editMarkerClass);
  if (task) {
    querySearchPort('');
    const {
      taskStage, taskLtLatitude, taskLtLongitude, taskRbLatitude, taskRbLongitude,
      mapScale, routeType, eta, tolerance, alertWaveHeight, alertWindSpeed, roll, pitch
    } = task;
    Object.assign(editTaskInfo, {
      id: task.id,
      code: task.name,
      mmsi: task.mmsi,
      type: taskStage,
      etd: new Date(getTimestampFromCustomFormatZ(task.ptdUtc, 'YYYY-MM-DD HH:mm:ss')),
      route: [...task.routeType],
      points: (task.points || []).map((point, idx) => {
        const {latitude, longitude, id, name} = point;
        if (id) {
          portOptionsChosen.value.push({
            id, lat: latitude, lon: longitude,
            text: name!,
            value: name!,
          });
        }
        if (!props.showMask) {
          if (idx === 0) {
            startMarker.setLngLat([longitude, latitude]).addTo(weatherStore.map as any);
            pointMarkers.value.push(startMarker as any);
          } else if (idx === task.points.length - 1) {
            endMarker.setLngLat([longitude, latitude]).addTo(weatherStore.map as any);
            pointMarkers.value.push(endMarker as any);
          } else {
            const marker = getParkMarker('经', idx, editMarkerClass);
            marker.setLngLat([longitude, latitude]).addTo(weatherStore.map as any);
            pointMarkers.value.push(marker as any);
          }
        }
        return {
          inputType: id ? RoutePointType.port : RoutePointType.point,
          lonDirection: lonDirection(longitude),
          lonValue: Math.abs(longitude).toFixed(2),
          latDirection: latDirection(latitude),
          latValue: Math.abs(latitude).toFixed(2),
          portId: id || undefined,
          lon: id ? longitude : undefined,
          lat: id ? latitude : undefined,
          name: id ? name : '',
        };
      }),
      speed: task.sog === undefined ? '12' : String(task.sog || 12),
      mapScale,
      // windSpeed: task.windSpeed === undefined ? '16' : String(task.windSpeed || 16),
      // waveHeight: task.waveHeight === undefined ? '2' : String(task.waveHeight || 2),
      alertWaveHeight: alertWaveHeight === undefined ? '4' : String(alertWaveHeight || 4),
      alertWindSpeed: alertWindSpeed === undefined ? '20' : String(alertWindSpeed || 20),
      roll: roll === undefined ? '' : String(roll || ''),
      pitch: pitch === undefined ? '' : String(pitch || ''),
      // safety: ,
      regionLeftTop: taskStage === TaskType.warStart ? {
        latDirection: taskLtLatitude! > 0 ? 'N' : 'S',
        latValue: String(Math.abs(taskLtLatitude!)),
        lonDirection: taskLtLongitude! > 0 ? 'E' : 'W',
        lonValue: String(Math.abs(taskLtLongitude!)),
      } : {...initRegionPoint},
      regionRightBottom: taskStage === TaskType.warStart ? {
        latDirection: taskRbLatitude! > 0 ? 'N' : 'S',
        latValue: String(Math.abs(taskRbLatitude!)),
        lonDirection: taskRbLongitude! > 0 ? 'E' : 'W',
        lonValue: String(Math.abs(taskRbLongitude!)),
      } : {...initRegionPoint},
    });
    if (routeType.includes(3)) {
      Object.assign(editTaskInfo, {
        eta: new Date(getTimestampFromCustomFormatZ(eta!, 'YYYY-MM-DD HH:mm:ss')),
        tolerance: String(Number(((tolerance || 0) / 3600).toFixed(2))),
      });
    } else {
      Object.assign(editTaskInfo, {
        eta: new Date(),
        tolerance: '1',
      });
    }
    if (routeType.includes(6)) {
      Object.assign(editTaskInfo, {
        diyPoints: task.diyPoints
      });
    }
    handleRegionUpdate();
  } else {
    Object.assign(editTaskInfo, initTaskInfo());
    if (userStore.taskPhase) editTaskInfo.type = userStore.taskPhase
    pointMarkers.value = [startMarker, endMarker];
  }
  show.value = true;
  nextTick(() => {
    formRef.value?.clearValidate();
  });
};

const customRouteRef = ref<HTMLDivElement>();

// ========== Import/Export/Map Pick Handlers ==========
const handlePickFromMap = () => {
  // 进入自定义航线绘制模式（mapEventStore 负责与其他模式互斥）
  mapEventStore.activate(MapTool.diyRouteDraw);
};
const handleImportFile = () => {
  // 创建一个隐藏的文件选择器
  const input = document.createElement('input');
  input.type = 'file';
  input.accept = '.xlsx,.xls,.csv';
  input.style.display = 'none';

  input.onchange = async () => {
    const file = input.files && input.files[0];
    if (!file) {
      input.remove();
      return;
    }
    loading.value = true;
    try {
      const formData = new FormData();
      formData.append('file', file);
      // 调用后端导入接口
      const resp: diyPointsData = await impDiyPoints(formData as any);
      // 规范化字段为 { longitude, latitude }
      editTaskInfo.diyPoints = resp.paths.map((p: any) => ({
        longitude: p[0],
        latitude: p[1],
      }));
      ElMessage({type: 'success', message: '导入成功'});

      customRouteRef.value?.setPoints(editTaskInfo.diyPoints)
    } catch (e) {
      ElMessage({type: 'warning', message: '导入失败，请检查文件内容或格式'});
    } finally {
      loading.value = false;
      input.remove();
    }
  };

  document.body.appendChild(input);
  input.click();
};
const handleDownloadTemplate = () => {
  const fullUrl = `/node/static/route-sample.xlsx`;
  // 触发浏览器下载
  const a = document.createElement('a');
  a.href = fullUrl;
  a.setAttribute('download', '');
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  ElMessage({
    type: 'success',
    message: '导入模板下载成功',
  });
};


const toggleActivePointSelect = (idx: number) => {
  if (!weatherStore.map) return;
  // 若当前已经在点选，则关闭点选；否则切换到新的行并确保工具激活
  if (mapEventStore.isActive(MapTool.pointPick)) {
    if (activeInputIdx.value === idx) {
      mapEventStore.deactivate(MapTool.pointPick);
    } else {
      activeInputIdx.value = idx; // 工具已在监听，切换索引即可
    }
  } else {
    activeInputIdx.value = idx;
    mapEventStore.activate(MapTool.pointPick);
  }
};

watch([
  () => editTaskInfo.mmsi,
  () => editTaskInfo.type,
  () => editTaskInfo.etd,
], () => {
  if (!editTaskInfo.id && !codeChangedManually.value) {
    const {mmsi, type, etd} = editTaskInfo;
    const taskOption = taskOptions.find(opt => opt.value === type);
    const time = getCustomLocalTimeFormat(etd, 'YYYY-MM-DD HH:mm:ss');
    editTaskInfo.code = `${mmsi}-${taskOption?.label}-${time}`;
  }
});

watch(show, () => {
  if (!show.value) {
    mapEventStore.deactivateAll();
    pointMarkers.value.forEach(marker => marker.remove());
    pointMarkers.value = [];
    updateTaskRegionSrc(weatherStore.map as any);
    formRef.value?.clearValidate();
  }
});

defineExpose({
  editTask: handleEditTask,
});

onMounted(() => {
  appStore.updateShipOptions();
});
</script>

<template>
  <ElDialog
      :class="['custom-dialog', 'task-edit-dialog', {'task-right': !props.center}]"
      v-model="show"
      :title="editTaskInfo.id ? '编辑任务' : '创建任务'"
      width="420"
      :before-close="onDialogBeforeClose"
      :modal="props.showMask"
      :modal-class="props.showMask ? '' : 'pointer-none-dialog-modal'"
      :close-on-click-modal="props.showMask"
      :align-center="props.center"
  >
    <ElScrollbar max-height="calc(100vh - 230px)">
      <ElForm ref="formRef" :rules="rules" :model="editTaskInfo" label-width="90" style="padding-right: 16px;">
        <ElFormItem prop="type" label="任务阶段" v-if="!userStore.taskPhase || router.path === '/task'">
          <ElSelect
              v-model="editTaskInfo.type"
              popper-class="custom-select-popper"
              placeholder="请选择任务阶段"
              @change="() => handleTaskStageUpdate()"
          >
            <ElOption
                v-for="option in taskOptions"
                :key="option.value"
                :value="option.value"
                :label="option.label"
            />
          </ElSelect>
        </ElFormItem>
        <ElFormItem prop="code" label="任务编号">
          <ElInput placeholder="请输入任务编号" v-model.trim="editTaskInfo.code"
                   @change="() => codeChangedManually = true"/>
        </ElFormItem>
        <ElFormItem prop="mmsi" label="舰船号">
          <ElSelect
              v-model="editTaskInfo.mmsi"
              popper-class="custom-select-popper"
              placeholder="请选择舰船号"
          >
            <ElOption
                v-for="option in appStore.shipOptions"
                :key="option.mmsi"
                :value="option.mmsi"
                :label="option.mmsi"
            />
          </ElSelect>
        </ElFormItem>
        <div class="form-one-line">
          <ElFormItem prop="etd" label="起航时间">
            <ElDatePicker
                v-model="editTaskInfo.etd"
                type="datetime"
                placeholder="请选择起航时间"
                style="flex: 1.6;margin-right: 0.5vw"
                :clearable="false"
            />
          </ElFormItem>
          <ElFormItem prop="speed" label="">
            <ElInput placeholder="" v-model="editTaskInfo.speed">
              <template #prefix><span class="custom-prefix">航速</span></template>
              <template #suffix>kts</template>
            </ElInput>
          </ElFormItem>
        </div>
        <div class="form-title">添加规划航线</div>
        <ElFormItem prop="route" label="航线类型">
          <ElSelect
              v-model="editTaskInfo.route"
              popper-class="custom-select-popper"
              placeholder="请选择航线类型"
              multiple
          >
            <ElOption
                v-for="option in routeOptions.slice(0, editTaskInfo.type === TaskType.taskPrepare ? 1 : undefined)"
                :key="option.value"
                :value="option.value"
                :label="option.label"
            />
          </ElSelect>
        </ElFormItem>
        <ElFormItem
            v-if="!(editTaskInfo.route.length === 1 && editTaskInfo.route[0] === 6)"
            v-for="(point, idx) in editTaskInfo.points"
            :label="getPointLabel(idx)"
            :prop="`point.${idx}`"
            class="point-form-item"
            :rules="[
            { required: true, validator: (_rule: any, _value: any, callback: any) => pointValidator(point, callback) },
          ]"
        >
          <ElIcon v-if="idx < editTaskInfo.points.length - 1" class="point-add-btn" @click="() => addPoint(idx)">
            <CirclePlus/>
          </ElIcon>
          <ElIcon v-if="idx > 0 && idx < editTaskInfo.points.length - 1" class="point-remove-btn"
                  @click="() => removePoint(idx)">
            <CircleClose/>
          </ElIcon>
          <ElSelect
              v-show="point.inputType === RoutePointType.port"
              v-model="point.portId"
              placeholder="名称/国家"
              popper-class="custom-select-popper"
              style="width: unset; flex: 1;"
              filterable
              remote
              clearable
              :remote-method="querySearchPort"
              :loading="portLoading"
              @change="(portId) => handleSelectPort(portId, idx)"
              @clear="() => handleClearPort(idx)"
          >
            <ElOption
                v-for="port in portOptions"
                :key="port.id"
                :value="port.id"
                :label="port.text"
            />
          </ElSelect>
          <ElInput
              v-show="point.inputType === RoutePointType.point"
              v-model="point.lonValue"
              style="width: unset; flex: 1;"
              placeholder="经度"
              @blur="() => handlePointUpdate(idx)"
          >
            <template #suffix>
              <span @click.stop="() => updatePointLonDirection(idx, point.lonDirection)">{{ point.lonDirection }}</span>
            </template>
          </ElInput>
          <ElInput
              v-show="point.inputType === RoutePointType.point"
              v-model="point.latValue"
              style="width: unset; flex: 1;"
              placeholder="纬度"
              @blur="() => handlePointUpdate(idx)"
          >
            <template #suffix>
              <span @click.stop="() => updatePointLatDirection(idx, point.latDirection)">{{ point.latDirection }}</span>
            </template>
          </ElInput>
          <span
              v-show="point.inputType === RoutePointType.point && !props.showMask"
              class="location-icon"
              @click="() => toggleActivePointSelect(idx)"
          >
           <ElIcon :color="isPointIdxActive(idx) ? '#1F93FF' : '#fff'"><LocationFilled/></ElIcon>
          </span>
          <ElSelect
              v-model="point.inputType"
              popper-class="custom-select-popper"
              style="width: 80px; margin-left: 2px;"
              @change="() => handlePointInputTypeChange(idx)"
          >
            <ElOption
                v-for="option in routePointOptions"
                :key="option.value"
                :value="option.value"
                :label="option.label"
            />
          </ElSelect>
        </ElFormItem>
        <ElFormItem
            v-if="editTaskInfo.type === TaskType.warStart"
            prop="regionLT"
            required
            label="任务区域"
            :rules="[
            { required: true, validator: (_rule: any, _value: any, callback: any) => regionValidator(editTaskInfo.regionLeftTop, callback) },
          ]"
        >
          <ElInput
              v-model="editTaskInfo.regionLeftTop.lonValue"
              style="width: unset; flex: 1;"
              placeholder="左上角经度"
              @blur="() => handleRegionUpdate()"
          >
            <template #suffix>
              <span @click.stop="() => updateRegionLonDirection(editTaskInfo.regionLeftTop)">{{
                  editTaskInfo.regionLeftTop.lonDirection
                }}</span>
            </template>
          </ElInput>
          <ElInput
              v-model="editTaskInfo.regionLeftTop.latValue"
              style="width: unset; flex: 1; margin-left: 6px;"
              placeholder="左上角纬度"
              @blur="() => handleRegionUpdate()"
          >
            <template #suffix>
              <span @click.stop="() => updateRegionLatDirection(editTaskInfo.regionLeftTop)">{{
                  editTaskInfo.regionLeftTop.latDirection
                }}</span>
            </template>
          </ElInput>
          <span
              v-show="!props.showMask"
              class="location-icon"
              @click="toggleRegionLTPick"
          >
            <ElIcon :color="isRegionLTPicking ? '#1F93FF' : '#fff'"><LocationFilled/></ElIcon>
          </span>
        </ElFormItem>
        <ElFormItem
            v-if="editTaskInfo.type === TaskType.warStart"
            prop="regionRB"
            label=""
            :rules="[
            { validator: (_rule: any, _value: any, callback: any) => regionValidator(editTaskInfo.regionRightBottom, callback) },
          ]"
        >
          <ElInput
              v-model="editTaskInfo.regionRightBottom.lonValue"
              style="width: unset; flex: 1;"
              placeholder="右下角经度"
              @blur="() => handleRegionUpdate()"
          >
            <template #suffix>
              <span @click.stop="() => updateRegionLonDirection(editTaskInfo.regionRightBottom)">{{
                  editTaskInfo.regionRightBottom.lonDirection
                }}</span>
            </template>
          </ElInput>
          <ElInput
              v-model="editTaskInfo.regionRightBottom.latValue"
              style="width: unset; flex: 1; margin-left: 6px;"
              placeholder="右下角纬度"
              @blur="() => handleRegionUpdate()"
          >
            <template #suffix>
              <span @click.stop="() => updateRegionLatDirection(editTaskInfo.regionRightBottom)">{{
                  editTaskInfo.regionRightBottom.latDirection
                }}</span>
            </template>
          </ElInput>
          <span
              v-show="!props.showMask"
              class="location-icon"
              @click="toggleRegionRBPick"
          >
            <ElIcon :color="isRegionRBPicking ? '#1F93FF' : '#fff'"><LocationFilled/></ElIcon>
          </span>
        </ElFormItem>
        <!--        <ElFormItem prop="mapScale" label="空间精度">-->
        <!--          <ElSelect-->
        <!--            v-model="editTaskInfo.mapScale"-->
        <!--            popper-class="custom-select-popper"-->
        <!--            placeholder="请选择空间精度"-->
        <!--          >-->
        <!--            <ElOption-->
        <!--              v-for="option in mapScaleOptions"-->
        <!--              :key="option.value"-->
        <!--              :value="option.value"-->
        <!--              :label="option.label"-->
        <!--            />-->
        <!--          </ElSelect>-->
        <!--        </ElFormItem>-->
        <ElFormItem v-if="editTaskInfo.type !== TaskType.taskPrepare" label-width="0">
          <ElFormItem
              prop="alertWindSpeed"
              label="气象阈值"
              :rules="[
                { required: true, message: '请输入最大风速', trigger: ['blur'] },
                { ...NumberRule },
                { validator: (_r:any, v:string, cb:any) => { if (Number(v) <= 0) cb('只能输入正数！'); else cb(); }, trigger: ['blur','change'] }
              ]"
              style="margin-bottom: 0;"
          >
            <ElInput placeholder="请输入" v-model="editTaskInfo.alertWindSpeed" style="width: 145px;">
              <template #prefix><span class="custom-prefix">风速</span></template>
              <template #suffix>kts</template>
            </ElInput>
          </ElFormItem>
          <ElFormItem
              prop="alertWaveHeight"
              :rules="[
                { required: true, message: '请输入最大浪高', trigger: ['blur'] },
                { ...NumberRule },
                { validator: (_r:any, v:string, cb:any) => { if (Number(v) <= 0) cb('只能输入正数！'); else cb(); }, trigger: ['blur','change'] }
              ]"
              style="margin-left: auto; margin-bottom: 0;"
          >
            <ElInput placeholder="请输入" v-model="editTaskInfo.alertWaveHeight"
                     style="width: 145px; margin-left: auto;">
              <template #prefix><span class="custom-prefix">浪高</span></template>
              <template #suffix>m</template>
            </ElInput>
          </ElFormItem>
        </ElFormItem>

        <ElFormItem v-if="editTaskInfo.route.includes(5)" label-width="0">
          <ElFormItem
              prop="roll"
              label="姿态阈值"
              :rules="[
                { required: true, message: '请输入横摇', trigger: ['blur'] },
                { ...NumberRule },
                { validator: (_r:any, v:string, cb:any) => { if (Number(v) <= 0) cb('只能输入正数！'); else cb(); }, trigger: ['blur','change'] }
              ]"
              style="margin-bottom: 0;"
          >
            <ElInput placeholder="请输入" v-model="editTaskInfo.roll" style="width: 145px;">
              <template #prefix><span class="custom-prefix">横摇</span></template>
              <template #suffix>°</template>
            </ElInput>
          </ElFormItem>
          <ElFormItem
              prop="pitch"
              :rules="[
                { required: true, message: '请输入纵摇', trigger: ['blur'] },
                { ...NumberRule },
                { validator: (_r:any, v:string, cb:any) => { if (Number(v) <= 0) cb('只能输入正数！'); else cb(); }, trigger: ['blur','change'] }
              ]"
              style="margin-left: auto; margin-bottom: 0;"
          >
            <ElInput placeholder="请输入" v-model="editTaskInfo.pitch" style="width: 145px;">
              <template #prefix><span class="custom-prefix">纵摇</span></template>
              <template #suffix>°</template>
            </ElInput>
          </ElFormItem>
        </ElFormItem>
        <ElFormItem
            v-if="editTaskInfo.route.includes(3)"
            prop="eta"
            label="到达时间"
            :rules="[
            { required: true, message: '请选择预计到达时间', trigger: ['blur'] },
          ]"
        >
          <ElDatePicker
              v-model="editTaskInfo.eta"
              type="datetime"
              placeholder="请选择预计到达时间"
              style="flex: 1;"
              :clearable="false"
          />
        </ElFormItem>
        <ElFormItem
            v-if="editTaskInfo.route.includes(3)"
            prop="tolerance"
            label="允许误差"
            :rules="[
              { required: true, message: '请输入固定时间到达允许误差', trigger: ['blur'] },
              { ...NumberRule },
              { validator: (_r:any, v:string, cb:any) => { if (Number(v) <= 0) cb('只能输入正数！'); else cb(); }, trigger: ['blur','change'] }
            ]"
        >
          <ElInput placeholder="请输入固定时间到达允许误差" v-model="editTaskInfo.tolerance">
            <template #suffix>小时</template>
          </ElInput>
        </ElFormItem>
        <!-- <ElFormItem prop="safety" label="安全评估">
          <ElSelect
            v-model="editTaskInfo.safety"
            popper-class="custom-select-popper"
            placeholder="请选择安全评估"
          >
            <ElOption
              v-for="option in options"
              :key="option.value"
              :value="option.value"
              :label="option.label"
            />
          </ElSelect>
        </ElFormItem> -->
      </ElForm>
      <div v-if="editTaskInfo.route.includes(6)" class="import-actions">
        <div class="form-title" style="margin-bottom: 0">
          添加自定义航线
        </div>
        <div class="button-line">
          <ElButton type="primary" size="small" @click="handlePickFromMap" v-if="router.path !== '/task'">从地图标点
          </ElButton>
          <ElButton type="primary" size="small" @click="handleImportFile">导入文件</ElButton>
          <ElButton type="primary" size="small" @click="handleDownloadTemplate">导入模板下载</ElButton>
        </div>
        <CustomRoute
            ref="customRouteRef"
            :map="weatherStore.map"
            v-model:points="editTaskInfo.diyPoints"
            :editable="true"
            :markerDraggable="true"
        />
      </div>
    </ElScrollbar>
    <div class="dialog-footer">
      <ElButton @click="() => handleCancelEdit()">取消</ElButton>
      <ElButton
          :loading="loading"
          type="primary"
          @click="() => handleSaveEdit()"
      >保存
      </ElButton>
    </div>
  </ElDialog>
</template>

<style lang="less">
.custom-dialog.task-edit-dialog.el-dialog {
  padding-right: 0;
  border: none;
  --el-dialog-margin-top: 50px;

  .el-dialog__body {
    padding: 0 0;
  }

  .dialog-footer {
    padding: 6px 76px 0 60px;
  }

  .el-form-item {
    margin-bottom: 16px;
  }

  .custom-prefix {
    margin-right: 6px;
  }

  .point-form-item {
    position: relative;

    .point-remove-btn,
    .point-add-btn {
      position: absolute;
      cursor: pointer;
      color: #fff;
      font-size: 18px;
    }

    .point-add-btn {
      left: -30px;
      bottom: -9px;
      transform: translate(-50%, 50%);
    }

    .point-remove-btn {
      left: -66px;
      top: 50%;
      transform: translate(-50%, -50%);
    }
  }

  .location-icon {
    cursor: pointer;
    background-color: rgba(0, 0, 0, 0.24);
    margin-left: 2px;
    display: inline-flex;
    width: 20px;
    align-self: stretch;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    border-radius: 4px;
  }
}

.custom-dialog.task-edit-dialog.el-dialog.task-right {
  margin-left: calc(100vw - 420px);
}

.form-one-line {
  width: 100%;
  display: flex;
  flex-flow: row nowrap;

  .el-form-item:first-of-type {
    width: 71%;
  }

  .el-form-item:last-of-type {
    .el-form-item__content {
      margin-left: 0 !important;
    }
  }
}

.form-title {
  color: #1F93FF;
  font-size: 18px;
  margin-bottom: 8px;
}


.import-actions {
  display: flex;
  flex-flow: column nowrap;
  gap: 12px;
  margin-bottom: 16px;

  .button-line {
    display: flex;
    flex-flow: row nowrap;
    justify-content: space-between;
    padding: 0 5%;

    .el-button {
      width: 30%;
      height: 30px;
      border-radius: 2px;
    }
  }
}

</style>
